package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.cac409club.mapper.UserMapper;
import com.example.cac409club.model.UserDO;
import com.example.constant.ResultCodeConstant;
import com.example.dto.InternalMessageDTO;
import com.example.exception.BusinessException;
import com.example.mapper.InternalMessageMapper;
import com.example.model.InternalMessageDO;
import com.example.service.impl.InternalMessageServiceImpl;
import com.example.util.EmailUtil;
import com.example.util.OTPUtil;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.test.context.ActiveProfiles;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ActiveProfiles("test")
public class InternalMessageServiceImplTest {

    @Mock
    private InternalMessageMapper internalMessageMapper;

    @Mock
    private UserMapper userMapper;

    @Mock
    private EmailUtil emailUtil;

    @Mock
    private OTPUtil otpUtil;

    @InjectMocks
    private InternalMessageServiceImpl internalMessageService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void testSendMessage_Success() {
        InternalMessageDTO internalMessageDTO = new InternalMessageDTO();
        internalMessageDTO.setSenderId(1);
        internalMessageDTO.setReceiverId(2);
        internalMessageDTO.setSubject("Test Subject");
        internalMessageDTO.setBody("Test Body");

        when(userMapper.selectById(1)).thenReturn(new UserDO());
        when(userMapper.selectById(2)).thenReturn(new UserDO());
        when(internalMessageMapper.insert(any())).thenReturn(1);

        assertDoesNotThrow(() -> assertTrue(internalMessageService.sendMessage(internalMessageDTO)));

        verify(internalMessageMapper, times(1)).insert(any());
    }

    @Test
    void testSendMessage_Failure_SenderNotFound() {
        InternalMessageDTO internalMessageDTO = new InternalMessageDTO();
        internalMessageDTO.setSenderId(1);
        internalMessageDTO.setReceiverId(2);
        internalMessageDTO.setSubject("Test Subject");
        internalMessageDTO.setBody("Test Body");

        when(userMapper.selectById(1)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.sendMessage(internalMessageDTO));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("发送者不存在", exception.getMessage());
    }

    @Test
    void testSendMessage_Failure_ReceiverNotFound() {
        InternalMessageDTO internalMessageDTO = new InternalMessageDTO();
        internalMessageDTO.setSenderId(1);
        internalMessageDTO.setReceiverId(2);
        internalMessageDTO.setSubject("Test Subject");
        internalMessageDTO.setBody("Test Body");

        when(userMapper.selectById(1)).thenReturn(new UserDO());
        when(userMapper.selectById(2)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.sendMessage(internalMessageDTO));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("接收者不存在", exception.getMessage());
    }

    @Test
    void testGetInbox_Success() {
        Integer userId = 1;
        InternalMessageDO messageDO = new InternalMessageDO();
        messageDO.setMessageId(1);
        messageDO.setSenderId(1);
        messageDO.setReceiverId(2);
        messageDO.setSubject("Test Subject");
        messageDO.setBody("Test Body");
        messageDO.setSendDate(new Date());
        messageDO.setReadStatus(false);
        messageDO.setCreateBy(1);
        messageDO.setUpdateBy(1);

        when(userMapper.selectById(1)).thenReturn(new UserDO());
        when(internalMessageMapper.selectList(any(QueryWrapper.class))).thenReturn(Arrays.asList(messageDO));

        List<InternalMessageDO> inbox = internalMessageService.getInbox(userId);
        assertNotNull(inbox);
        assertEquals(1, inbox.size());
        assertEquals(messageDO, inbox.get(0));
    }

    @Test
    void testGetInbox_Failure_UserNotFound() {
        Integer userId = 1;

        when(userMapper.selectById(1)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.getInbox(userId));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("用户不存在", exception.getMessage());
    }

    @Test
    void testMarkAsRead_Success() {
        Integer messageId = 1;
        InternalMessageDO messageDO = new InternalMessageDO();
        messageDO.setMessageId(1);
        messageDO.setSenderId(1);
        messageDO.setReceiverId(2);
        messageDO.setSubject("Test Subject");
        messageDO.setBody("Test Body");
        messageDO.setSendDate(new Date());
        messageDO.setReadStatus(false);
        messageDO.setCreateBy(1);
        messageDO.setUpdateBy(1);

        when(internalMessageMapper.selectById(1)).thenReturn(messageDO);
        when(internalMessageMapper.updateById(any())).thenReturn(1);

        assertDoesNotThrow(() -> assertTrue(internalMessageService.markAsRead(messageId)));

        verify(internalMessageMapper, times(1)).updateById(any());
    }

    @Test
    void testMarkAsRead_Failure_MessageNotFound() {
        Integer messageId = 1;

        when(internalMessageMapper.selectById(1)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.markAsRead(messageId));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("消息不存在", exception.getMessage());
    }

    @Test
    void testDeleteMessage_Success() {
        Integer messageId = 1;
        InternalMessageDO messageDO = new InternalMessageDO();
        messageDO.setMessageId(1);
        messageDO.setSenderId(1);
        messageDO.setReceiverId(2);
        messageDO.setSubject("Test Subject");
        messageDO.setBody("Test Body");
        messageDO.setSendDate(new Date());
        messageDO.setReadStatus(false);
        messageDO.setCreateBy(1);
        messageDO.setUpdateBy(1);

        when(internalMessageMapper.selectById(1)).thenReturn(messageDO);
        when(internalMessageMapper.deleteById(1)).thenReturn(1);

        assertDoesNotThrow(() -> assertTrue(internalMessageService.deleteMessage(messageId)));

        verify(internalMessageMapper, times(1)).deleteById(1);
    }

    @Test
    void testDeleteMessage_Failure_MessageNotFound() {
        Integer messageId = 1;

        when(internalMessageMapper.selectById(1)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.deleteMessage(messageId));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("消息不存在", exception.getMessage());
    }

    @Test
    void testSendNotificationEmail_Success() {
        Integer userId = 1;
        String subject = "Test Subject";
        String body = "Test Body";

        UserDO userDO = new UserDO();
        userDO.setUserId(1);
        userDO.setEmail("test@example.com");

        when(userMapper.selectById(1)).thenReturn(userDO);
        when(emailUtil.sendEmail("test@example.com", subject, body)).thenReturn(true);

        assertDoesNotThrow(() -> assertTrue(internalMessageService.sendNotificationEmail(userId, subject, body)));

        verify(emailUtil, times(1)).sendEmail("test@example.com", subject, body);
    }

    @Test
    void testSendNotificationEmail_Failure_UserNotFound() {
        Integer userId = 1;
        String subject = "Test Subject";
        String body = "Test Body";

        when(userMapper.selectById(1)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.sendNotificationEmail(userId, subject, body));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("用户不存在", exception.getMessage());
    }

    @Test
    void testSendOTPEmail_Success() {
        Integer userId = 1;

        UserDO userDO = new UserDO();
        userDO.setUserId(1);
        userDO.setEmail("test@example.com");

        when(userMapper.selectById(1)).thenReturn(userDO);
        when(emailUtil.sendEmail("test@example.com", anyString(), anyString())).thenReturn(true);

        assertDoesNotThrow(() -> assertTrue(internalMessageService.sendOTPEmail(userId)));

        verify(emailUtil, times(1)).sendEmail("test@example.com", anyString(), anyString());
    }

    @Test
    void testSendOTPEmail_Failure_UserNotFound() {
        Integer userId = 1;

        when(userMapper.selectById(1)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.sendOTPEmail(userId));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("用户不存在", exception.getMessage());
    }

    @Test
    void testVerifyOTP_Success() {
        Integer userId = 1;
        String otpCode = "123456";

        UserDO userDO = new UserDO();
        userDO.setUserId(1);
        userDO.setEmail("test@example.com");

        when(userMapper.selectById(1)).thenReturn(userDO);
        when(otpUtil.verifyOTP("123456")).thenReturn(true);

        assertDoesNotThrow(() -> assertTrue(internalMessageService.verifyOTP(userId, otpCode)));

        verify(otpUtil, times(1)).verifyOTP("123456");
    }

    @Test
    void testVerifyOTP_Failure_UserNotFound() {
        Integer userId = 1;
        String otpCode = "123456";

        when(userMapper.selectById(1)).thenReturn(null);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.verifyOTP(userId, otpCode));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("用户不存在", exception.getMessage());
    }

    @Test
    void testVerifyOTP_Failure_OTPIncorrect() {
        Integer userId = 1;
        String otpCode = "123456";

        UserDO userDO = new UserDO();
        userDO.setUserId(1);
        userDO.setEmail("test@example.com");

        when(userMapper.selectById(1)).thenReturn(userDO);
        when(otpUtil.verifyOTP("123456")).thenReturn(false);

        BusinessException exception = assertThrows(BusinessException.class, () -> internalMessageService.verifyOTP(userId, otpCode));
        assertEquals(ResultCodeConstant.CODE_000001, exception.getCode());
        assertEquals("验证码错误", exception.getMessage());
    }
}